package utils.sl651;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * SL651协议报文解析核心类
 * 
 * 实现SL651-2014标准的上行报文解析功能
 */
public class SL651AscillMessageParser {
    
    /**
     * 解析上行报文
     * 
     * @param rawMessage 原始报文字符串（十六进制格式）
     * @return 解析后的报文对象
     */
    public static SL651Message parseUplinkMessage(String rawMessage) {
        SL651Message message = new SL651Message();
        try {
            // 解析报文头部
            parseMessageHeader(rawMessage, message);
            // 二次验证CRC校验码
            boolean crcValid = SL651CrcUtil.verifyAscillMessageCrc(rawMessage);
            message.setCrcValid(crcValid);
            
            if (!crcValid) {
                message.setErrorMessage("CRC校验失败");
                return message;
            }
            // 解析数据部分
            parseMessageData(rawMessage, message);
            message.setValid(true);
            
        } catch (Exception e) {
            message.setErrorMessage("解析异常: " + e.getMessage());
            message.setValid(false);
        }
        return message;
    }
    
    /**
     * 解析报文头部信息
     */
    private static void parseMessageHeader(String message, SL651Message messageObj) {
        int pos = 2; // 跳过起始符
        
        // 解析中心站地址（1字节HEX编码，2个ASCII字符）
        String centerAddr = message.substring(pos, pos + 2);
        messageObj.setCenterAddress(centerAddr);
        pos += 2;
        
        // 解析遥测站地址（5字节HEX编码，10个ASCII字符）
        String stationAddr = message.substring(pos, pos + 10);
        messageObj.setStationAddress(stationAddr);
        pos += 10;
        
        // 解析密码（2字节HEX编码，4个ASCII字符）
        String password = message.substring(pos, pos + 4);
        messageObj.setPassword(password);
        pos += 4;
        
        // 解析功能码（1字节HEX编码，2个ASCII字符）
        String functionCode = message.substring(pos, pos + 2);
        messageObj.setFunctionCode(functionCode);
        pos += 2;
        
        // 解析报文上行标识及长度（2字节HEX编码，4个ASCII字符）
        String flagAndLength = message.substring(pos, pos + 4);
        messageObj.setFlagAndLength(flagAndLength);
        pos += 4;
        
        // 验证数据起始符STX（02）
        String stx = message.substring(pos, pos + 2);
        if (!"02".equals(stx)) {
            throw new IllegalArgumentException("数据起始符错误，应为02，实际为: " + stx);
        }
        pos += 2;
        
        // 提取CRC校验码（2字节HEX编码，4个ASCII字符）
        String crcCode = message.substring(message.length() - 4);
        messageObj.setCrcCode(crcCode);
    }
    
    /**
     * 解析报文数据部分
     */
    private static void parseMessageData(String message, SL651Message messageObj) {
        // 计算数据部分起始位置：SOH(2) + 中心站地址(2) + 遥测站地址(10) + 密码(4) + 功能码(2) + 报文上行标识及长度(4) + STX(2)
        int dataStartPos = 2 + 2 + 10 + 4 + 2 + 4 + 2;
        
        // 计算数据结束位置（去掉ETX和CRC）
        int dataEndPos = message.length() - 6; // 减去ETX(2字节) + CRC(4字节)
        
        if (dataStartPos >= dataEndPos) {
            // 无数据内容（如链路维持报文）
            return;
        }

        // 提取原始数据部分
        String rawData = message.substring(dataStartPos, dataEndPos);
        messageObj.setRawData(rawData);

        // 解析流水号（2字节HEX编码，4个ASCII字符）
        if (rawData.length() >= 4) {
            String serialNumber = rawData.substring(0, 4);
            messageObj.setSerialNumber(serialNumber);
        }

        // 解析发报时间（12字节ASCII - YYMMDDHHmmSS）
        if (rawData.length() >= 16) { // 4(流水号) + 12(发报时间)
            String reportTime = rawData.substring(4, 16);
            messageObj.setReportTime(SL651CommonUtil.parseBcdTime(reportTime));
        }

        // 如果数据只包含流水号和时间，则不需要进一步解析
        if (rawData.length() <= 16) {
            return;
        }
        
        // 实际数据内容（去掉流水号和发报时间）
        String dataContent = rawData.substring(16);
        
        // 根据功能码选择解析方式
        String functionCode = messageObj.getFunctionCode();
        
        if (functionCode == null) {
            return;
        }
        
        switch (functionCode) {
            case SL651Protocol.FUNC_LINK_MAINTAIN:
                // 链路维持报文无数据内容
                break;
                
            case SL651Protocol.FUNC_TEST_REPORT:
            case SL651Protocol.FUNC_TIMER_REPORT:
            case SL651Protocol.FUNC_ADD_REPORT:
                // 解析ASCII格式数据
                parseAsciiDataContent(dataContent, messageObj);
                break;

            case SL651Protocol.FUNC_HOUR_REPORT:
                // 解析小时报文数据
                parseHourReportData(dataContent, messageObj);
                break;
                
            default:
                // 其他功能码暂时作为原始数据处理
                messageObj.addDataElement("RAW_DATA", dataContent);
                break;
        }
    }
    
    /**
     * 解析ASCII格式数据内容
     * 根据SL651协议6.6.2节要求：
     * 1. 报文正文信息组编码由要素（参数）标识符与相应数据构成，标识符编列在前，数据编列在后
     * 2. 各要素（参数）标识符、数据之间均用"空格"作为分隔符
     * 3. 流水号及发报时间后不带"空格"分隔符
     * 4. 报文正文最后的1个空格不得省略
     */
    private static void parseAsciiDataContent(String hexData, SL651Message messageObj) {
        try {
            // 将十六进制转换为ASCII字符串
            String asciiData = hexData;
            
            // 按照SL651协议要求解析数据
            // 数据格式为："标识符 数据 标识符 数据 "（注意最后有一个空格）
            parseSl651FormattedData(asciiData, messageObj);
            
        } catch (Exception e) {
            messageObj.setErrorMessage("ASCII数据解析失败: " + e.getMessage());
        }
    }
    
    /**
     * 按照SL651协议格式解析数据内容
     * 数据格式：要素标识符 空格 数据 空格 要素标识符 空格 数据 空格...
     * 最后一个空格不得省略
     */
    private static void parseSl651FormattedData(String asciiData, SL651Message messageObj) {
        // 去除首尾空格，但保留中间的空格分隔符
        String trimmedData = asciiData.trim();
        if (trimmedData.isEmpty()) {
            return;
        }
        
        // 按空格分割数据，但需要正确处理标识符和数据的配对
        String[] parts = trimmedData.split("\\s+");
        
        for (int i = 0; i < parts.length; i++) {
            String element = parts[i];
            
            // 解析站点标识符
            if ("ST".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_STATION_ID, parts[i + 1]);
                i++; // 跳过下一个元素
            }
            // 解析站点分类码
            else if ("H".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_STATION_TYPE, parts[i + 1]);
                i++;
            }
            // 解析观测时间
            else if ("TT".equals(element) && i + 1 < parts.length) {
                String time = parts[i + 1];
                String timeStr = SL651CommonUtil.parseBcdTime2(time);
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                LocalDateTime dateTime = LocalDateTime.parse(timeStr, formatter);
                messageObj.addDataElement(SL651Protocol.ELEM_OBSERVE_TIME, timeStr);
                messageObj.setObserveDateTime(dateTime);
                i++;
            }
            // 解析降水量数据
            else if ("PJ".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_CURRENT_RAINFALL, parts[i + 1]);
                i++;
            }
            // 解析累计降水量
            else if ("PT".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_TOTAL_RAINFALL, parts[i + 1]);
                i++;
            }
            // 解析水位数据
            else if ("Z".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_WATER_LEVEL, parts[i + 1]);
                i++;
            }
            // 解析流量数据
            else if ("Q".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_FLOW_RATE, parts[i + 1]);
                i++;
            }
            // 解析电压数据
            else if ("VT".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_VOLTAGE, parts[i + 1]);
                i++;
            }
            // 解析水温
            else if ("TW".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_WATER_TEMP, parts[i + 1]);
                i++;
            }
            // 解析PH值
            else if ("PH".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_PH, parts[i + 1]);
                i++;
            }
            // 解析溶解氧
            else if ("DO".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_DISSOLVED_OXYGEN, parts[i + 1]);
                i++;
            }
            // 解析电导率
            else if ("COND".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_CONDUCTIVITY, parts[i + 1]);
                i++;
            }
            // 解析浊度
            else if ("TU".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_TURBIDITY, parts[i + 1]);
                i++;
            }
            // 暂时注释缺失常量的解析代码
            /*
            // 解析温度 - 使用新的常量
            else if ("T".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement(SL651Protocol.ELEM_TEMPERATURE, parts[i + 1]);
                i++;
            }
            */
            // 暂时注释缺失常量的其他解析代码
            // === 侧缝计专用数据元素解析 ===
            // 解析位移量
            else if ("DP".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement("DP", parts[i + 1]);
                i++;
            }
            // 解析应变（注意：这里的ST是应变，不是站址）
            else if ("ST".equals(element) && i + 1 < parts.length && isNumeric(parts[i + 1])) {
                messageObj.addDataElement("STRAIN", parts[i + 1]);
                i++;
            }
            // 解析倾角
            else if ("INC".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement("INC", parts[i + 1]);
                i++;
            }
            // 解析振动
            else if ("VIB".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement("VIB", parts[i + 1]);
                i++;
            }
            // 解析内部温度
            else if ("TEMP".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement("TEMP", parts[i + 1]);
                i++;
            }
            // 解析电池电量
            else if ("BAT".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement("BAT", parts[i + 1]);
                i++;
            }
            // 解析设备状态
            else if ("STAT".equals(element) && i + 1 < parts.length) {
                messageObj.addDataElement("STAT", parts[i + 1]);
                i++;
            }
            // 解析遥测站分类码（P开头的）
            else if (element.startsWith("P") && element.length() == 2) {
                messageObj.addDataElement("STATION_TYPE_CODE", element);
            }
            // 解析其他可能的数据元素
            else if ("DT".equals(element) && i + 1 < parts.length) {
                // 时间间隔数据
                messageObj.addDataElement("DT", parts[i + 1]);
                i++;
            }
            else if ("GH".equals(element) && i + 1 < parts.length) {
                // 闸上水位
                messageObj.addDataElement("GH", parts[i + 1]);
                i++;
            }
            else if ("GT".equals(element) && i + 1 < parts.length) {
                // 闸下水位
                messageObj.addDataElement("GT", parts[i + 1]);
                i++;
            }
            else if ("RH".equals(element) && i + 1 < parts.length) {
                // 湿度
                messageObj.addDataElement("RH", parts[i + 1]);
                i++;
            }
        }
    }
    
    /**
     * 解析小时报文数据
     */
    private static void parseHourReportData(String hexData, SL651Message messageObj) {
        try {
            // 小时报文包含ASCII数据和二进制数据的混合格式
            String asciiData = hexData;
            
            // 先按ASCII方式解析基本数据元素
            parseAsciiDataContent(hexData, messageObj);
            
            // 解析特殊的时间序列数据
            String[] elements = asciiData.trim().split("\\s+");
            
            for (int i = 0; i < elements.length; i++) {
                String element = elements[i];
                
                // 解析5分钟间隔雨量数据
                if ("DRP".equals(element) && i + 1 < elements.length) {
                    String drpData = elements[i + 1];
                    messageObj.addDataElement(SL651Protocol.ELEM_5MIN_RAINFALL, drpData);
                    // 解析DRP数据为数组
                    parseDrpData(drpData, messageObj);
                    i++;
                }
                // 解析5分钟间隔水位数据
                else if ("DRZ1".equals(element) && i + 1 < elements.length) {
                    String drzData = elements[i + 1];
                    messageObj.addDataElement(SL651Protocol.ELEM_5MIN_WATER_LEVEL, drzData);
                    // 解析DRZ1数据为数组
                    parseDrzData(drzData, messageObj);
                    i++;
                }
            }
            
        } catch (Exception e) {
            messageObj.setErrorMessage("小时报文数据解析失败: " + e.getMessage());
        }
    }
    
    /**
     * 解析DRP（5分钟间隔雨量）数据
     */
    private static void parseDrpData(String drpHex, SL651Message messageObj) {
        try {
            // DRP数据：24个十六进制字符，每2个字符表示5分钟雨量
            if (drpHex == null || drpHex.length() != 24) {
                messageObj.addDataElement("DRP_PARSE_ERROR", "DRP数据长度不正确，期望24字符，实际" + (drpHex != null ? drpHex.length() : 0));
                return;
            }
            
            String[] rainfallData = new String[12]; // 1小时=12个5分钟
            double totalRainfall = 0;
            int validCount = 0;
            
            for (int i = 0; i < 12; i++) {
                String hexValue = drpHex.substring(i * 2, i * 2 + 2);
                if ("FF".equals(hexValue)) {
                    rainfallData[i] = "无效数据";
                } else {
                    try {
                        int value = Integer.parseInt(hexValue, 16);
                        double rainfall = value * 0.1; // 假设精度0.1mm
                        rainfallData[i] = String.format("%.1fmm", rainfall);
                        totalRainfall += rainfall;
                        validCount++;
                    } catch (NumberFormatException e) {
                        rainfallData[i] = "格式错误";
                    }
                }
            }
            
            // 存储解析后的雨量数据
            messageObj.addDataElement("DRP_PARSED", String.join(",", rainfallData));
            messageObj.addDataElement("DRP_TOTAL_RAINFALL", String.format("%.1fmm", totalRainfall));
            messageObj.addDataElement("DRP_VALID_COUNT", String.valueOf(validCount));
            messageObj.addDataElement("DRP_VALID_RATE", String.format("%.1f%%", (validCount * 100.0 / 12)));
            
        } catch (Exception e) {
            messageObj.addDataElement("DRP_PARSE_ERROR", "解析异常: " + e.getMessage());
        }
    }
    
    /**
     * 解析DRZ1（5分钟间隔水位）数据
     */
    private static void parseDrzData(String drzHex, SL651Message messageObj) {
        try {
            // DRZ1数据：48个十六进制字符，每4个字符表示5分钟水位
            if (drzHex == null || drzHex.length() != 48) {
                messageObj.addDataElement("DRZ1_PARSE_ERROR", "DRZ1数据长度不正确，期望48字符，实际" + (drzHex != null ? drzHex.length() : 0));
                return;
            }
            
            String[] waterLevelData = new String[12]; // 1小时=12个5分钟
            double maxLevel = Double.MIN_VALUE;
            double minLevel = Double.MAX_VALUE;
            double totalLevel = 0;
            int validCount = 0;
            
            for (int i = 0; i < 12; i++) {
                String hexValue = drzHex.substring(i * 4, i * 4 + 4);
                if ("FFFF".equals(hexValue)) {
                    waterLevelData[i] = "无效数据";
                } else {
                    try {
                        int value = Integer.parseInt(hexValue, 16);
                        double level = value * 0.01; // 假设精度0.01m
                        waterLevelData[i] = String.format("%.2fm", level);
                        
                        maxLevel = Math.max(maxLevel, level);
                        minLevel = Math.min(minLevel, level);
                        totalLevel += level;
                        validCount++;
                    } catch (NumberFormatException e) {
                        waterLevelData[i] = "格式错误";
                    }
                }
            }
            
            // 存储解析后的水位数据
            messageObj.addDataElement("DRZ1_PARSED", String.join(",", waterLevelData));
            
            if (validCount > 0) {
                messageObj.addDataElement("DRZ1_MAX_LEVEL", String.format("%.2fm", maxLevel));
                messageObj.addDataElement("DRZ1_MIN_LEVEL", String.format("%.2fm", minLevel));
                messageObj.addDataElement("DRZ1_AVG_LEVEL", String.format("%.2fm", totalLevel / validCount));
                messageObj.addDataElement("DRZ1_LEVEL_RANGE", String.format("%.2fm", maxLevel - minLevel));
                messageObj.addDataElement("DRZ1_VALID_COUNT", String.valueOf(validCount));
                messageObj.addDataElement("DRZ1_VALID_RATE", String.format("%.1f%%", (validCount * 100.0 / 12)));
            }
            
        } catch (Exception e) {
            messageObj.addDataElement("DRZ1_PARSE_ERROR", "解析异常: " + e.getMessage());
        }
    }
    
    /**
     * 判断字符串是否为数字
     */
    private static boolean isNumeric(String str) {
        if (str == null || str.trim().isEmpty()) {
            return false;
        }
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}